package com.nextbusmn.server;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.nextbusmn.server.JDOWrappers.BusStopJDOWrapper;
import com.nextbusmn.server.JDOWrappers.ScheduleDateJDOWrapper;
import com.nextbusmn.server.JDOWrappers.StopTimeJDOWrapper;
import com.nextbusmn.server.dataobjects.BusStopData;
import com.nextbusmn.server.dataobjects.StopTimeData;

/**
 *  Servlet to load schedule data
 *  @author Trent Olson
 */
public class LoadScheduleServlet extends HttpServlet {
	
  // source URL for schedule data; I've left this blank intentionally
  // so the servlet isn't accidentally called & our data overwritten!
	private String source = "";
	
		// test data for only route 133
		//"http://trentolson.ca/dev/route133.zip";
		
		// test data for only small routes: 133, 134, 141 and 780
		//"http://trentolson.ca/dev/smallRoutesOnly.zip";
		
		// NEW complete test data: 67, 133, 131, 141 and 780
		//"http://trentolson.ca/dev/newTestData.zip";
		
		// official data source, but doesn't work; needs "true" as 
		// second argument to ScheduleSource constructor:
		//"ftp://gisftp.metc.state.mn.us/google_transit.zip";
	
	// set source object for data: first argument is URL as string,
	// second argument uses elevated privileges if true
	private ScheduleSource sched = new ScheduleSource(source, false);
	
  // method used when load schedule is used as a local class in the 
  // remote API; just calls the doGet with nulls for request & response
	public void loadSchedule() throws IOException, ServletException {
		doGet(null, null);
	}
	
  // handle GET requests to the servlet
	public void doGet(HttpServletRequest req,
			HttpServletResponse resp) throws IOException, ServletException {
			
		// create a stream to read from a zip archive
		ZipInputStream zin = new ZipInputStream(sched.getScheduleStream());
		 // get the first entry in the zip archive 	
		ZipEntry zipentry = zin.getNextEntry();
		
    // initialize variables for the contents of each file
		String routeData = null;
		String shapeData = null;
		String tripData = null;
		String stopData = null;
		String stopTimeData = null;
		String calDateData = null;
		
    // get the timestamp from the file and set the date for our schedule data
		ScheduleDateJDOWrapper.setCurrentScheduleDate(new Date(zipentry.getTime()));	
		
		// for each entry in the zip archive, read data to a string
		while (zipentry != null) {	
			if (zipentry.getName().equals("routes.txt")) {
				routeData = getStringFromStream(zin);
			} else if (zipentry.getName().equals("trips.txt")) {
				tripData = getStringFromStream(zin);
			} else if (zipentry.getName().equals("shapes.txt")) {
				shapeData = getStringFromStream(zin);
			} else if (zipentry.getName().equals("calendar_dates.txt")) {
				calDateData = getStringFromStream(zin);
			} else if (zipentry.getName().equals("stops.txt")) {
				stopData = getStringFromStream(zin);
			} else if (zipentry.getName().equals("stop_times.txt")) {
				stopTimeData = getStringFromStream(zin);
			}
			// close this entry & get the next one
			zin.closeEntry();
			zipentry = zin.getNextEntry();
		}
		 // close the archive
		zin.close();
    
    // read each string with the appropriate parser method.
    // note routes, trips, and stopTimes all read by routes parser
    // in order to build the relationships between entities  
		ScheduleDataReader.readRoutes(routeData, tripData, stopTimeData);
		ScheduleDataReader.readStops(stopData);
		ScheduleDataReader.readShapes(shapeData);
		ScheduleDataReader.readCalendarDates(calDateData);
		
		System.out.println("Load & link complete");
	}
	
  /**
   *  Helper method to read String from a zip input stream
   */
	private String getStringFromStream(ZipInputStream zin) {
		try {
	        return new Scanner(zin).useDelimiter("\\A").next();
	    } catch (NoSuchElementException e) {
	        return "";
	    }
	}
}
